﻿/**************************************************************
 *
 * 唯一标识：36b8fda9-6066-4cfd-8ff9-c68c77a9e30c
 * 命名空间：Sgr.RoleAggregate
 * 创建时间：2023/8/7 15:55:17
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using Sgr.Domain.Entities.Auditing;
using Sgr.Domain.Entities;
using System.Collections.Generic;
using System.Linq;
using Sgr.Exceptions;
using System.Data;
using Sgr.UPMS.Events;
using Sgr.UPMS.Domain.Users;
using System.Threading.Tasks;
using System;
using MediatR;
using System.Runtime.Versioning;

namespace Sgr.UPMS.Domain.Roles
{
    /// <summary>
    /// 角色
    /// </summary>
    public class Role : CreationAndModifyAuditedEntity<long, long>, IAggregateRoot, IOptimisticLock, IMustHaveOrg<long>, IHaveCode
    {
        private List<RoleResource> _resources;

        /// <summary>
        /// 资源清单
        /// </summary>
        public IEnumerable<RoleResource> Resources => _resources.AsReadOnly();

        /// <summary>
        /// 角色
        /// </summary>
        private Role()
        {
            _resources = new List<RoleResource>();
            State = EntityStates.Normal;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="code"></param>
        /// <param name="roleName"></param>
        /// <param name="orgId"></param>
        /// <param name="orderNumber"></param>
        /// <param name="remarks"></param>
        internal Role(string code, string roleName, long orgId, int orderNumber = 0, string? remarks = null)
            : this()
        {
            Code = code;
            RoleName = roleName;
            OrderNumber = orderNumber;
            Remarks = remarks;
            OrgId = orgId;
        }

        /// <summary>
        /// 角色编码
        /// </summary>
        public string Code { get; private set; } = string.Empty;

        /// <summary>
        /// 角色名称
        /// </summary>
        public string RoleName { get; internal protected set; } = "";

        /// <summary>
        /// 排序号
        /// </summary>
        public int OrderNumber { get; set; } = 0;

        /// <summary>
        /// 备注
        /// </summary>
        public string? Remarks { get; set; }

        /// <summary>
        /// 状态
        /// </summary>
        public EntityStates State { get; internal protected set; } = EntityStates.Normal;

        #region 角色->资源管理

        /// <summary>
        /// 验证权限码格式
        /// </summary>
        private bool IsValidPermissionCode(string permissionCode)
        {
            return !string.IsNullOrWhiteSpace(permissionCode)
                && permissionCode.Length <= 500;
        }

        /// <summary>
        /// 确保角色具备指定的功能权限点（如缺失则自动添加）
        /// </summary>
        /// <param name="permissionNames">功能权限点名称集合</param>
        public void EnsureFunctionalPermissions(string[] permissionNames)
        {
            if (permissionNames == null || permissionNames.Length == 0)
                return;

            bool hasChange = false;

            foreach (var permission in permissionNames)
            {
                if (!IsValidPermissionCode(permission))
                    continue;

                if (!_resources.Any(r => r.ResourceType == ResourceType.FunctionalPermission && r.ResourceCode == permission))
                {
                    _resources.Add(new RoleResource(ResourceType.FunctionalPermission, permission));
                    hasChange = true;
                }
            }

            if(hasChange)
                this.AddDomainEvent(new RoleAuthChangedDomainEvent(this.Id));
        }

        /// <summary>
        /// 差异更新功能权限
        /// </summary>
        /// <param name="resourceType"></param>
        /// <param name="resourceCodes"></param>
        public bool DifferenceUpdateFunctionalPermission(ResourceType resourceType, string[]? resourceCodes)
        {
            if (resourceType != ResourceType.FunctionalPermission)
                throw new ArgumentException("资源类型必须是功能权限", nameof(resourceType));

            bool hasChange = false;

            // 获取当前权限字典
            var currentPermissions = new HashSet<string>(_resources
                .Where(r => r.ResourceType == ResourceType.FunctionalPermission)
                .Select(r => r.ResourceCode));

            // 新权限集合（过滤无效的权限码）
            var newPermissions = (resourceCodes ?? Array.Empty<string>())
                .Where(IsValidPermissionCode)
                .ToHashSet();

            // 需要删除的权限
            var permissionsToRemove = currentPermissions.Except(newPermissions);
            foreach (var permission in permissionsToRemove)
            {
                var resource = _resources.FirstOrDefault(r => r.ResourceType == resourceType && r.ResourceCode == permission);
                if (resource != null)
                {
                    _resources.Remove(resource);
                    hasChange = true;
                }
            }

            // 需要添加的权限
            var permissionsToAdd = newPermissions.Except(currentPermissions);
            foreach (var permission in permissionsToAdd)
            {
                var resource = _resources.FirstOrDefault(r => r.ResourceType == resourceType && r.ResourceCode == permission);
                if (resource == null)
                {
                    resource = new RoleResource(resourceType, permission);
                    _resources.Add(resource);
                    hasChange = true;
                }
            }

            if (hasChange)
                this.AddDomainEvent(new RoleAuthChangedDomainEvent(this.Id));

            return hasChange;
        }

        /// <summary>
        /// 是否存在某权限
        /// </summary>
        /// <param name="resourceType"></param>
        /// <param name="resourceCode"></param>
        /// <returns></returns>
        public bool AnyPermission(ResourceType resourceType, string resourceCode)
        {
            return _resources.Any(f => f.ResourceType == resourceType && f.ResourceCode == resourceCode);
        }

        #endregion 角色->资源管理

        #region 调整角色状态

        /// <summary>
        /// 调整实体状态
        /// </summary>
        /// <param name="state"></param>
        public void ChangeEntityStates(EntityStates state)
        {
            if (this.State != state)
            {
                this.State = state;
                this.AddDomainEvent(new RoleAuthChangedDomainEvent(this.Id));
            }
        }

        #endregion 调整角色状态

        /// <summary>
        /// 标记其发待删除
        /// </summary>
        public void MarkForDeletion()
        {
            this.AddDomainEvent(new RoleAuthChangedDomainEvent(this.Id));
        }

        #region IOptimisticLock (乐观锁)

        /// <summary>
        /// 行版本
        /// </summary>
        public long RowVersion { get; set; }

        #endregion IOptimisticLock (乐观锁)

        #region IMustHaveOrg  (如果一个实体实现该接口，那么必须存储实体所在组织的ID.)

        /// <summary>
        /// 所属组织
        /// </summary>
        public long OrgId { get; internal protected set; }

        #endregion IMustHaveOrg  (如果一个实体实现该接口，那么必须存储实体所在组织的ID.)
    }
}